package com.seng.resourcetycoon.gui.models;

import com.seng.resourcetycoon.core.enums.ResourceType;

import java.util.Map;
import java.util.Objects;
import java.util.concurrent.ConcurrentHashMap;

public class LoadBearer {

    /**
     * A map representing the maximum requirement capacities for each {@link ResourceType}.
     */
    private final Map<ResourceType, Integer> requiredResources;

    public LoadBearer(Map<ResourceType,Integer> requiredResources) {
        this.requiredResources = requiredResources;
    }

    /**
     * A map storing the current loaded quantities of resources in the carts.
     */
    private final ConcurrentHashMap<ResourceType, Integer> energyResources = new ConcurrentHashMap<>();

    /**
     * Tries to fill the cart with a specified quantity of a resource.
     *
     * @param resourceType The type of resource to add.
     * @param quantity    The amount of the resource to add.
     * @return The actual quantity of the resource added to the cart.
     * @throws IllegalArgumentException if the resourceType is null or quantity is negative.
     */
    public int tryAddToCart(ResourceType resourceType, int quantity) {
        // 参数校验
        if (resourceType == null) {
            throw new IllegalArgumentException("Resource type cannot be null.");
        }
        if (quantity < 0) {
            System.out.print("Quantity must be non-negative.");
            return 0;
        }

        int spaceAvailable = getAvailableCapacityForResource(resourceType);
        int filledQuantity = Math.min(spaceAvailable, quantity);

        if (filledQuantity > 0) {
            // 更新资源数量
            energyResources.compute(resourceType, (type, currentQuantity) -> {
                int newQuantity = (currentQuantity == null ? 0 : currentQuantity) + filledQuantity;
                System.out.printf("Added " + filledQuantity + " of resource " + type + " to the cart.\n");
                return newQuantity;
            });
        } else {
            // 没有可用空间时记录日志
            System.out.printf("No space available for resource " + resourceType + ".\n");
        }
        return filledQuantity;
    }

    public Map<ResourceType, Integer> getRequiredResources() {
        return requiredResources;
    }

    /**
     * Constructs a cart with predefined maximum capacities for each resource type.
     *
     * This method calculates the available capacity for a given resource type.
     * It takes into account the current consumption and the maximum allowed for
     * the resource, ensuring that the calculated capacity is never negative.
     *
     * @param resourceType A ResourceType defining the resource for which to calculate the available capacity.
     * @return The available capacity for the specified resource type.
     */
    public int getAvailableCapacityForResource(ResourceType resourceType) {
        if (requiredResources == null) {
            throw new IllegalStateException("Resources and requiredResources must not be null.");
        }
        int currentCapacity = energyResources.getOrDefault(resourceType,0);
        int requiredCapacity = requiredResources.getOrDefault(resourceType, 0);

        if (requiredCapacity < 0) {
            throw new IllegalArgumentException("Required capacity for resourceType cannot be negative.");
        }
        return Math.max(requiredCapacity - currentCapacity, 0);
    }

    /**
     * Appends the description and quantity of resource capacities from the provided map to the given string builder.
     *
     * @param sb           The string builder to accumulate the formatted output.
     * @param capacityMap  A map containing the key-value pairs of {@link ResourceType} and their respective quantities.
     */
    private void appendResourceCapacity(StringBuilder sb, Map<ResourceType, Integer> capacityMap) {
        if(capacityMap == null){
            return;
        }
        for (Map.Entry<ResourceType, Integer> entry : capacityMap.entrySet()) {
            ResourceType resourceType = entry.getKey();
            int quantity = entry.getValue();
            sb.append(resourceType.getDescription()).append(" x ").append(quantity).append("\n");
        }
    }

    /**
     * Generates and returns a string report listing the maximum requirements for each resource type.
     *
     * @return A human-readable string detailing the maximum requirement capacities for each resource type.
     */
    public String reportRequirementCapacities() {
        StringBuilder output = new StringBuilder("Requirement：");
        appendResourceCapacity(output, requiredResources);
        return output.toString().trim();
    }

    /**
     * Generates and returns a string report listing the current loaded capacities for each resource type.
     *
     * @return A human-readable string detailing the currently loaded capacities for each resource type.
     */
    public String reportLoadedCapacities() {
        StringBuilder output = new StringBuilder("Loaded: ");
        appendResourceCapacity(output, energyResources);
        return output.toString().trim();
    }


    public boolean isFullForResourceType(ResourceType resourceType) {
         return Objects.equals(energyResources.getOrDefault(resourceType, 0), requiredResources.getOrDefault(resourceType, 0));
    }

    /**
     * 检查所有资源需求是否都被满足。
     * @return 是否所有需求都已满足
     */
    public boolean allRequirementsMet() {
        if(energyResources.isEmpty()){
            return false;
        }
        return energyResources.entrySet().stream()
                .allMatch(entry -> entry.getValue().equals(requiredResources.getOrDefault(entry.getKey(), 0)));
    }

    public int getQuantityForResource(ResourceType resourceType) {
        return energyResources.getOrDefault(resourceType,0);
    }
}
